/**
 * Copyright 2009 cestum.org
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.cestum.cave.presenter.rpc
{
	import com.google.protobuf.Message;
	import com.hurlant.math.BigInteger;
	
	import flash.events.Event;
	
	import org.cestum.cave.logger.Logger;
	import org.goverla.collections.HashMap;
	import org.waveprotocol.wave.examples.fedone.rpc.RpcFinished;

	public class CaveChannel implements ISocketDataCallBack
	{	
		private var thisSocket:CaveSocket;
		public var hostName:String;
		public var portNo:String;
		private var connectionNotClosed:Boolean;
		private var lastSequenceNumber:BigInteger;
		private const INCR:BigInteger = new BigInteger("1");
		private var activeMethodMap:HashMap;
		
		[MessageDispatcher]
		public var dispatcher:Function;
		
		public function CaveChannel()	{
		}
		
		public function init():void {
			Logger.log("Initiating Socket connection...");
			activeMethodMap = new HashMap();
			thisSocket = new CaveSocket(this, hostName, int(portNo));
		}
		
		public function changeHostPort(host:String, port:int):void {
			Logger.log("Changing Host Port...");
			this.hostName = host;
			this.portNo = new String(port);
			if (thisSocket == null ||
				!thisSocket.connected) {
				thisSocket = new CaveSocket(this, host, port);
				return;
			}
			//TODO
			//dispatchEvent Connection Disconnect...
			thisSocket.close();
			//wait till Connection is closed;
			while(true) {
				if (!connectionNotClosed) {
					thisSocket == null;
					break;
				}
			}
			if (thisSocket != null) {
				//TODO check forceClose;
				thisSocket ==null;
			}
			thisSocket = new CaveSocket(this, host, port);
		}
		
		public function generateEvent(event:Event):void {
			dispatcher(event);
		}
		
		public function incrementAndGet():BigInteger {
			if (lastSequenceNumber == null) 
				lastSequenceNumber = new BigInteger("0");
			lastSequenceNumber = lastSequenceNumber.add(INCR);
			return lastSequenceNumber;
		}
		/**
		 * Call method - 
		 * Prepares the ConnectCallback,
		 * connects to the server, get the data and pass it back to the RPC Callback
		 **/
		public function callMethod(msg:Message, responseProto:Message, callback:Function ):CaveRPCController {
			//Create
			var sequenceNo:BigInteger = incrementAndGet();
			var controller:CaveRPCController = createController(callback);
			activeMethodMap.addItem(sequenceNo.intValue(), controller);
			thisSocket.sendMessage(sequenceNo, msg, responseProto);
			return controller;
		}
		
		private function createController(callback:Function):CaveRPCController {
			return new CaveRPCController(this,callback);
		}
		
		public function message(sequenceNo:BigInteger, message:Message):void {
			var controller:CaveRPCController = activeMethodMap.getItem(sequenceNo.intValue()) as CaveRPCController;
			if (message instanceof RpcFinished) {
				var finished:RpcFinished = message as RpcFinished;
				if (finished.failed) {
					controller.failure(finished.errorText);
				} else {
					controller.response(null);
				}
			} else {
				controller.response(message);
			}
		}
		
		public function unknown(sequenceNo:BigInteger, messageType:String):void {
			
		}
		

	}
}